home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / ABUSESRC.ZIP / AbuseSrc / macabuse / imlib / specs.c < prev    next >
C/C++ Source or Header  |  1997-05-20  |  22KB  |  1,010 lines

  1. #include "system.h"
  2. #include "image.hpp"
  3. #include "palette.hpp"
  4. #include "specs.hpp"
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <ctype.h>
  8. #include <fcntl.h>
  9. #include "jmalloc.hpp"
  10. #include <math.h>
  11. #include "dprint.hpp"
  12. #ifndef __MAC__
  13. #include <sys/types.h>
  14. #include <sys/stat.h>
  15. #endif
  16.  
  17. #ifdef __MAC__
  18. extern char *macify_name(char *s);
  19. #endif
  20.  
  21. char *spec_types[]={"Invalid type",             // 0
  22.                     "Color table",              // 1
  23.                     "Palette",                  // 2
  24.                     "Invalid Type",             // 3
  25.                     "Image",                    // 4
  26.                             "Fore Tile",
  27.                     "Back Tile",
  28.                     "Character",
  29.                     "8 Morph",
  30.                     "16 Morph",
  31.             "Grue objs",
  32.             "Extern WAV",
  33.             "DMX MUS",
  34.             "Patched morph",
  35.             "Normal file",
  36.             "Compress1 file",
  37.             "Vector Image",
  38.             "Light list",
  39.             "Grue fgmap",
  40.             "Grue bgmap",
  41.             "Data array",
  42.             "Character2",
  43.             "Particle",
  44.             "Extern lcache"
  45. };
  46.  
  47.  
  48. int total_files_open=0;
  49. char spec_main_file[100];
  50.  
  51. static char *spec_prefix=NULL;
  52. static char *save_spec_prefix=NULL;
  53.  
  54. static jFILE spec_main_jfile((FILE*)0);
  55. static int spec_main_fd = -1;
  56. static long spec_main_offset = -1;
  57. static spec_directory spec_main_sd;
  58.  
  59. static int fast_load_fd = -1;
  60. static int fast_load_mode = 0;
  61.  
  62. void set_filename_prefix(char *prefix)
  63. {
  64.   if (spec_prefix) { jfree(spec_prefix); }
  65.   if (prefix) 
  66.   {
  67.     spec_prefix=strcpy((char *)jmalloc(strlen(prefix)+2,"prefix_name"),prefix);
  68.     int len=strlen(prefix);
  69.     if (prefix[len-1]!='\\' && prefix[len-1]!='/')
  70.     {
  71.       spec_prefix[len]='/';
  72.       spec_prefix[len+1]=0;
  73.     }
  74.   }
  75.  
  76.   else spec_prefix=NULL;
  77. }
  78.  
  79. char *get_filename_prefix()
  80. {
  81.   return spec_prefix;
  82. }
  83.  
  84.  
  85. void set_save_filename_prefix(char *save_prefix)
  86. {
  87.   if (save_spec_prefix) { jfree(save_spec_prefix); }
  88.   if (save_prefix) 
  89.   {
  90.     save_spec_prefix=strcpy((char *)jmalloc(strlen(save_prefix)+1,"prefix_name"),save_prefix);
  91.     int len=strlen(save_prefix);
  92.     if (save_prefix[len-1]!='\\' && save_prefix[len-1]!='/')
  93.     {
  94.       save_spec_prefix[len]='/';
  95.       save_spec_prefix[len+1]=0;
  96.     }
  97.   }
  98.   else save_spec_prefix=NULL;
  99. }
  100.  
  101. char *get_save_ilename_prefix()
  102. {
  103.   return save_spec_prefix;
  104. }
  105.  
  106. int search_order=SPEC_SEARCH_OUTSIDE_INSIDE;
  107.  
  108. static void (*no_space_handle_fun)()=NULL;
  109.  
  110. void set_no_space_handler(void (*handle_fun)())
  111. {
  112.   no_space_handle_fun=handle_fun;
  113. }
  114.  
  115.  
  116. bFILE::bFILE()
  117. {
  118.   rbuf_size=8192;
  119.   rbuf=(unsigned char *)jmalloc(rbuf_size,"File read buffer");
  120.   rbuf_start=rbuf_end=0;  
  121.  
  122.   wbuf_size=8192;
  123.   wbuf=(unsigned char *)jmalloc(wbuf_size,"File write buffer");
  124.   wbuf_end=0;  
  125. }
  126.  
  127. bFILE::~bFILE()
  128.   if (rbuf) jfree(rbuf);
  129.   flush_writes();
  130.   if (wbuf) jfree(wbuf);
  131. }
  132.  
  133. int bFILE::flush_writes() 
  134. {
  135.   if (wbuf_end!=0)
  136.   {
  137.     long ret=unbuffered_write(wbuf,wbuf_end);
  138.     if (ret!=wbuf_end && no_space_handle_fun)
  139.       no_space_handle_fun();
  140.       
  141.     wbuf_end=0;
  142.     return ret;
  143.   }
  144.   return 0;
  145. }
  146.  
  147. int bFILE::read(void *buf, size_t count)       // returns number of bytes read, calls unbuffer_read
  148. {
  149.   if (!allow_read_buffering()) 
  150.     return unbuffered_read(buf,count);
  151.  
  152.   int total_read=0,error=0;
  153.   if (!count) return 0;
  154.   while (count && !error)
  155.   {
  156.     if (rbuf_start<rbuf_end)
  157.     {
  158.       int avail_size=rbuf_end-rbuf_start;
  159.       int copy_size=avail_size>count ? count : avail_size;
  160.       memcpy(buf,rbuf+rbuf_start,copy_size);
  161.       buf=(void *)(((unsigned char *)buf)+copy_size);
  162.       rbuf_start+=copy_size;
  163.       if (rbuf_start>=rbuf_end)    
  164.       {
  165.                 if (rbuf_end!=rbuf_size)  // buffer wasn't full before so there is no way we can complete read
  166.                   error=1;
  167.                 rbuf_start=rbuf_end=0;
  168.       }
  169.       total_read+=copy_size;
  170.       count-=copy_size;
  171.     } else
  172.     {
  173.       rbuf_end=unbuffered_read(rbuf,rbuf_size);
  174.       if (rbuf_end==0) error=1;
  175.       rbuf_start=0;
  176.     }
  177.   }
  178.   return total_read;
  179. }
  180.  
  181.  
  182. int bFILE::write(void *buf, size_t count)      // returns number of bytes written
  183.   if (allow_write_buffering())
  184.   {
  185.     int total_written=0;
  186.     while (count)
  187.     {
  188.       int copy_size=wbuf_end+count<=wbuf_size ? count :  wbuf_size-wbuf_end;           
  189.       memcpy(wbuf+wbuf_end,buf,copy_size);
  190.       wbuf_end+=copy_size;
  191.       count-=copy_size;
  192.       buf=(void *)(((char *)buf)+copy_size);
  193.       if (wbuf_end==wbuf_size)
  194.         if (flush_writes()!=wbuf_size)
  195.       return total_written;
  196.       
  197.       total_written+=copy_size;      
  198.     }
  199.     return total_written;
  200.   } else
  201.   {
  202.     long ret=unbuffered_write(buf,count);
  203.     if (ret!=count && no_space_handle_fun)
  204.       no_space_handle_fun();
  205.   }
  206.   return 0;
  207. }
  208.  
  209. int bFILE::seek(long offset, int whence) // whence=SEEK_SET, SEEK_CUR, SEEK_END, ret=0=success
  210. {  
  211. //    rbuf_start=rbuf_end=0;
  212. //    unbuffered_seek(offset,SEEK_SET);
  213.  
  214.   long realpos=unbuffered_tell();
  215.   long curpos=realpos-rbuf_end+rbuf_start;
  216.   if (whence==SEEK_CUR) offset+=curpos;
  217.   else if (whence==SEEK_END) offset=file_size()-offset;
  218.  
  219.   if (offset<realpos-rbuf_end || offset>=realpos)
  220.   {
  221.     rbuf_start=rbuf_end=0;
  222.     unbuffered_seek(offset,SEEK_SET);
  223.   } else  
  224.     rbuf_start=rbuf_end-(realpos-offset);
  225.   return 1;
  226. }
  227.  
  228. int bFILE::tell()
  229. {
  230.   return unbuffered_tell()-rbuf_end+rbuf_start+
  231.          wbuf_end;    // if this a write file, add on how much we've written
  232. }
  233.  
  234. int bFILE::allow_read_buffering() { return 1; }
  235. int bFILE::allow_write_buffering() { return 1; }
  236.  
  237. void bFILE::set_read_buffer_size(long size)
  238. {
  239.   unbuffered_seek(tell(),SEEK_SET);
  240.   rbuf_start=rbuf_end=0;
  241.   if (rbuf)
  242.     jfree(rbuf);
  243.   rbuf_size=size;
  244.   rbuf=(unsigned char *)jmalloc(rbuf_size,"File buffer");
  245. }
  246.  
  247. void set_spec_main_file(char *filename, int Search_order)
  248. {
  249.   dprintf("Specs : main file set to %s\n",filename);
  250.   strcpy(spec_main_file,filename);
  251.   search_order=Search_order;
  252.   
  253. #ifdef __MAC__
  254.   spec_main_jfile.open_external(filename,"rb",O_BINARY|O_RDONLY);
  255.   spec_main_fd = spec_main_jfile.get_fd();
  256.   spec_main_sd.startup(&spec_main_jfile);
  257. #else
  258.   spec_main_jfile.open_external(filename,"rb",O_RDONLY);
  259.   spec_main_fd = spec_main_jfile.get_fd();
  260.   spec_main_sd.startup(&spec_main_jfile);
  261. #endif
  262. }
  263.  
  264. void fast_load_start_recording(char *filename)
  265. {
  266. #ifdef __MAC__
  267.   fast_load_fd = ::open(macify_name(filename),O_BINARY|O_CREAT|O_RDWR);
  268. #else
  269.   fast_load_fd = ::open(filename,O_CREAT|O_RDWR,S_IRWXU | S_IRWXG | S_IRWXO);
  270. #endif
  271.     fast_load_mode = 1;
  272. }
  273.  
  274. void fast_load_stop_recording()
  275. {
  276.     fast_load_mode = 0;
  277. }
  278.  
  279. void fast_load_start_reloading(char *filename)
  280. {
  281. #ifdef __MAC__
  282.   fast_load_fd = ::open(macify_name(filename),O_BINARY|O_RDONLY);
  283. #else
  284.   fast_load_fd = ::open(filename,O_RDONLY);
  285. #endif
  286.     fast_load_mode = 2;
  287. }
  288.  
  289. void fast_load_stop_reloading()
  290. {
  291.     fast_load_mode = 0;
  292. }
  293.  
  294. jFILE::jFILE(FILE *file_pointer)                       // assumes fp is at begining of file
  295. {
  296.   access=0;
  297.   fd=-1;
  298.   file_length=0;
  299.   start_offset=0;
  300.   flags=JFILE_CLONED;
  301. }
  302.  
  303. void jFILE::open_external(char *filename, char *mode, int flags)
  304. {
  305.   int skip_size=0;
  306.   char tmp_name[200];
  307.   if (spec_prefix)
  308.     sprintf(tmp_name,"%s%s",spec_prefix,filename);
  309.   else strcpy(tmp_name,filename);
  310.  
  311. //  int old_mask=umask(S_IRWXU | S_IRWXG | S_IRWXO);
  312. #ifdef __WATCOMC__
  313.   flags|=O_BINARY;
  314. #endif
  315.   if (flags&O_WRONLY)
  316.   {
  317.     if ((flags&O_APPEND)==0) 
  318.     {
  319.       skip_size=1;
  320.       int errval = unlink(tmp_name);
  321.     }
  322.  
  323.     flags-=O_WRONLY;
  324.     flags|=O_CREAT|O_RDWR;
  325.  
  326. #ifdef __MAC__
  327.         fd=open(macify_name(tmp_name),flags);
  328. #else
  329.     fd=open(tmp_name,flags,S_IRWXU | S_IRWXG | S_IRWXO);
  330. #endif
  331.   } else 
  332. #ifdef __MAC__
  333.     fd=open(macify_name(tmp_name),flags);
  334. #else
  335.     fd=open(tmp_name,flags);
  336. #endif
  337.  
  338. //  umask(old_mask);
  339.   if (fd>=0 && !skip_size)
  340.   {
  341.     file_length=lseek(fd,0,SEEK_END);
  342.     if ((flags&O_APPEND)==0)
  343.       lseek(fd,0,SEEK_SET);
  344.     else
  345.         current_offset = file_length;
  346.     start_offset=0;
  347.   } else 
  348.   {
  349.     file_length=0;
  350.     start_offset=0;
  351.   }
  352. }
  353.  
  354.  
  355. class null_file : public bFILE     // this file type will use virtual opens inside of a spe
  356. {
  357.   public :
  358.   virtual int open_failure() { return 1; }
  359.   virtual int unbuffered_read(void *buf, size_t count)   { return 0; }
  360.   virtual int unbuffered_write(void *buf, size_t count)  { return 0; }
  361.   virtual int unbuffered_seek(long offset, int whence)   { return 0; }
  362.  
  363.   virtual int unbuffered_tell() { return 0; }
  364.   virtual int file_size() { return 0; }
  365.   virtual ~null_file() { ; }
  366. } ; 
  367.  
  368.  
  369. static bFILE *(*open_file_fun)(char *,char *)=NULL;
  370. int (*verify_file_fun)(char *,char *)=NULL;
  371.  
  372. void set_file_opener(bFILE *(*open_fun)(char *, char *))
  373. {
  374.   open_file_fun=open_fun;
  375. }
  376.  
  377. bFILE *open_file(char *filename, char *mode)
  378. {
  379.   if (!verify_file_fun || verify_file_fun(filename,mode))
  380.   {
  381.     if (open_file_fun)
  382.       return open_file_fun(filename,mode);
  383.     else return new jFILE(filename,mode);
  384.   } else return new null_file;
  385. }
  386.  
  387. void jFILE::open_internal(char *filename, char *mode, int flags)
  388. {
  389.   int wr=0;
  390.   for (char *s=mode;*s;s++) 
  391.     if (toupper(*s)=='A' || toupper(*s)=='W')
  392.       wr=1;
  393.  
  394.   if (wr)
  395.     fd=-1;                 // only allow extern file openings for writing
  396.   else
  397.   {
  398.        fd = spec_main_fd;
  399.     if (fd>=0)                    // if we were able to open the main file, see if it's in there
  400.     {
  401.       start_offset=0;
  402.       spec_entry *se=spec_main_sd.find(filename);
  403.       if (se)    
  404.       {
  405.                 start_offset=se->offset;
  406.                 current_offset = 0;
  407.                 file_length=se->size;
  408.                 rbuf_start=rbuf_end=0;
  409.       } else 
  410.       {
  411.                 close(fd);
  412.                 fd=-1;
  413.       }
  414.     }  
  415.   }
  416. }
  417.  
  418. jFILE::jFILE(char *filename, char *access_string)      // same as fopen parameters
  419. {
  420.  flags=access=0;  
  421.  char *s=access_string;
  422.   for (;*s;s++) 
  423.     if (toupper(*s)=='R') access=O_RDONLY;
  424.  
  425.   for (s=access_string;*s;s++) 
  426.     if (toupper(*s)=='W')      
  427.       if (access)
  428.         access=O_RDWR;
  429.       else access=O_WRONLY;
  430.  
  431.   for (s=access_string;*s;s++) 
  432.     if (toupper(*s)=='A')      
  433.       access|=O_APPEND|O_WRONLY;
  434.  
  435.   file_length=start_offset=-1;
  436.   current_offset = 0;
  437.  
  438.   fd=-1;
  439.   if (search_order==SPEC_SEARCH_OUTSIDE_INSIDE)
  440.     open_external(filename,access_string,access);
  441.  
  442.   if (fd<0)
  443.     open_internal(filename,access_string,access);
  444.  
  445.   if (fd<0 && search_order==SPEC_SEARCH_INSIDE_OUTSIDE)
  446.     open_external(filename,access_string,access);
  447.  
  448.   total_files_open++;
  449. }
  450.  
  451. jFILE::~jFILE()
  452. {
  453.   flush_writes();
  454.   if (fd>=0 && !(flags&JFILE_CLONED))
  455.   {
  456.     total_files_open--;
  457.     if (fd != spec_main_fd)
  458.         close(fd);
  459.   }
  460. }
  461.  
  462. int jFILE::unbuffered_tell()
  463. {
  464. //    int ret = ::lseek(fd,0,SEEK_CUR) - start_offset;
  465. //    if (ret != current_offset)
  466. //        fprintf(stderr,"Bad tell %d\n",current_offset);
  467.     return current_offset;
  468. }
  469.  
  470. int jFILE::unbuffered_read(void *buf, size_t count)
  471. {
  472.     long len;
  473.  
  474.     if (fd == spec_main_fd)
  475.     {
  476.         switch (fast_load_mode)
  477.         {
  478.         case 0:
  479.             if (current_offset+start_offset != spec_main_offset)
  480.                 spec_main_offset = lseek(fd, start_offset+current_offset, SEEK_SET);
  481.             
  482.             len = ::read(fd,(char*)buf,count);
  483.             break;
  484.         case 1:
  485.             if (current_offset+start_offset != spec_main_offset)
  486.                 spec_main_offset = lseek(fd, start_offset+current_offset, SEEK_SET);
  487.             
  488.             len = ::read(fd,(char*)buf,count);
  489.             ::write(fast_load_fd,(char*)&len,sizeof(len));
  490.             ::write(fast_load_fd,(char*)buf,count);
  491.             break;
  492.         case 2:
  493.             ::read(fast_load_fd,(char*)&len,sizeof(len));
  494.             len = ::read(fast_load_fd,(char*)buf,len);
  495.             break;
  496.         }
  497.         
  498.         spec_main_offset += len;
  499.     }
  500.     else
  501.     {
  502.         switch (fast_load_mode)
  503.         {
  504.         case 0:
  505.           len = ::read(fd,(char*)buf,count);
  506.           break;
  507.         case 1:
  508.           len = ::read(fd,(char*)buf,count);
  509.             ::write(fast_load_fd,(char*)&len,sizeof(len));
  510.             ::write(fast_load_fd,(char*)buf,count);
  511.           break;
  512.         case 2:
  513.             ::read(fast_load_fd,(char*)&len,sizeof(len));
  514.             len = ::read(fast_load_fd,(char*)buf,len);
  515.             if (count != len)
  516.                 printf("short read! %d:%d\n",current_offset,len);
  517.           break;
  518.       }
  519.     }
  520.     current_offset += len;
  521.     return len;
  522. }
  523.  
  524. int jFILE::unbuffered_write(void *buf, size_t count)
  525. {
  526.   long ret = ::write(fd,(char*)buf,count);
  527.     current_offset += ret;
  528.     return ret;
  529. }
  530.  
  531. int jFILE::unbuffered_seek(long offset, int whence) // whence=SEEK_SET, SEEK_CUR, SEEK_END, ret=0=success
  532. {
  533.     long ret;
  534.     
  535.     if (fast_load_mode == 2)
  536.     {
  537.         switch (whence)
  538.         {
  539.     case SEEK_SET : 
  540.          current_offset = start_offset+offset;
  541.          break;
  542.     case SEEK_END : 
  543.         current_offset = start_offset+file_length-offset;
  544.         break;
  545.     case SEEK_CUR : 
  546.         current_offset += offset;
  547.         break;
  548.     default:
  549.         ret = -1;
  550.         break;
  551.     }
  552.         return current_offset;
  553.     }
  554.     
  555.   switch (whence)
  556.   {
  557.     case SEEK_SET : 
  558.     { ret = lseek(fd,start_offset+offset,SEEK_SET); } break;
  559.     case SEEK_END : 
  560.     { ret = lseek(fd,start_offset+file_length-offset,SEEK_SET); } break;
  561.     case SEEK_CUR : 
  562.     { ret = lseek(fd,offset,SEEK_CUR); } break;
  563.     default:
  564.         ret = -1;
  565.         break;
  566.   }
  567.   if (ret>=0)
  568.   {
  569.       current_offset = ret - start_offset;
  570.       if (spec_main_fd == fd)
  571.           spec_main_offset = ret;
  572.       return ret;
  573.   }
  574.   else
  575.       return -1;  // if a bad whence, then failure
  576. }
  577.  
  578.  
  579. unsigned char bFILE::read_byte()
  580. { unsigned char x;
  581.   read(&x,1);
  582.   return x;
  583. }
  584.  
  585. unsigned short bFILE::read_short()
  586.   unsigned short x;
  587.   read(&x,2); 
  588.   return int_to_local(x);
  589. }
  590.  
  591.  
  592. unsigned long bFILE::read_long()
  593.   unsigned long x;
  594.   read(&x,4); 
  595.   return long_to_local(x);
  596. }
  597.  
  598. void bFILE::write_byte(unsigned char x)
  599. {
  600.   write(&x,1);
  601. }
  602.  
  603. void bFILE::write_short(unsigned short x)
  604.   x=int_to_local(x);
  605.   write(&x,2);
  606. }
  607.  
  608.  
  609. void bFILE::write_long(unsigned long x)
  610. {
  611.   x=long_to_local(x);
  612.   write(&x,4);
  613. }
  614.  
  615. void bFILE::write_double(double x)
  616. {
  617.   double a;
  618.   write_long((long)(modf(x,&a)*(double)(1<<32-1)));
  619.   write_long((long)a);
  620. }
  621.  
  622. double bFILE::read_double()
  623. {
  624.   long a,b;
  625.   a=read_long();
  626.   b=read_long();
  627.   return (double)b+a/(double)(1<<32-1);
  628. }
  629.  
  630. spec_directory::~spec_directory()
  631. {
  632.  
  633.   if (total)
  634.   {
  635.     jfree(data);
  636.     jfree(entries);
  637.   }
  638. }
  639.  
  640. void spec_entry::print()
  641. {
  642.   printf("%15s%25s%8ld%8ld\n",spec_types[type],name,size,offset);
  643. }
  644.  
  645. void spec_directory::calc_offsets()
  646. {
  647.   spec_entry **e;
  648.   int i;
  649.   long o=SPEC_SIG_SIZE+2;
  650.   if (total)
  651.   { 
  652.     for (i=0,e=entries;i<total;i++,e++)          // calculate the size of directory info
  653.     {
  654.       o+=1+1+strlen((*e)->name)+1 +1 +8;
  655.     }
  656.  
  657.     for (i=0,e=entries;i<total;i++,e++)          // calculate offset for each entry
  658.     {
  659.       (*e)->offset=o;
  660.       o+=(*e)->size;
  661.     }
  662.   }
  663. }
  664.  
  665. spec_entry *spec_directory::find(char *name, int type)
  666. {
  667.   int i;
  668.   spec_entry **e;
  669.   for (i=0,e=entries;i<total;i++,e++)
  670.     if (!strcmp((*e)->name,name) && (*e)->type==type)
  671.       return (*e);
  672.   return NULL;
  673. }
  674.  
  675. spec_entry *spec_directory::find(char *name)
  676. {
  677.   int i;
  678.   spec_entry **e;
  679.   for (i=0,e=entries;i<total;i++,e++)
  680.     if (!strcmp((*e)->name,name))
  681.       return (*e);
  682.   return NULL;
  683. }
  684.  
  685. long spec_directory::find_number(char *name)
  686. {
  687.   int i;
  688.   spec_entry **e;
  689.   for (i=0,e=entries;i<total;i++,e++)
  690.     if (!strcmp((*e)->name,name))
  691.       return i;
  692.   return -1;
  693. }
  694.  
  695. spec_entry *spec_directory::find(int type)
  696. {
  697.   int i;
  698.   spec_entry **e;
  699.   for (i=0,e=entries;i<total;i++,e++)
  700.     if ((*e)->type==type)
  701.       return (*e);
  702.   return NULL;
  703. }
  704.  
  705. long spec_directory::type_total(int type)
  706. {
  707.   int i,x=0;
  708.   spec_entry **e;
  709.   for (i=0,e=entries;i<total;i++,e++)
  710.     if ((*e)->type==type) x++;
  711.   return x;
  712. }
  713.  
  714. long spec_directory::find_number(int type)
  715. {
  716.   int i;
  717.   spec_entry **e;
  718.   for (i=0,e=entries;i<total;i++,e++)
  719.     if ((*e)->type==type)
  720.       return i;
  721.   return -1;
  722. }
  723.  
  724. void spec_directory::print()
  725. {
  726.   spec_entry **se;
  727.   int i;
  728.   printf("[   Entry type   ][   Entry name   ][  Size  ][ Offset ]\n"); 
  729.   for (i=0,se=entries;i<total;i++,se++)
  730.     (*se)->print();
  731. }
  732.  
  733.  
  734. void spec_directory::startup(bFILE *fp)
  735. {
  736.   char buf[256];
  737.   fp->read(buf,8);
  738.   buf[9]=0;
  739.   size=0;
  740.   if (!strcmp(buf,SPEC_SIGNATURE))
  741.   {    
  742.     total=fp->read_short();   
  743.     entries=(spec_entry **)jmalloc(sizeof(spec_entry *)*total,"spec_directory::entries");
  744.     long start=fp->tell();
  745.  
  746.     int i=0;
  747.     for (i=0;i<total;i++)
  748.     {            
  749.       fp->read(buf,2);
  750.       long entry_size=sizeof(spec_entry)+(unsigned char)buf[1];
  751.       entry_size=(entry_size+3)&(~3);
  752.       fp->read(buf,(unsigned char)buf[1]);
  753.       fp->read(buf,9);
  754.  
  755.       size+=entry_size;
  756.     }
  757.     data=jmalloc(size,"spec_directory::data");
  758.     char *dp=(char *)data;
  759.     fp->seek(start,SEEK_SET);
  760.     for (i=0;i<total;i++)
  761.     {            
  762.       spec_entry *se=(spec_entry *)dp;
  763.       entries[i]=se;
  764.  
  765.       unsigned char len,flags,type;
  766.       fp->read(&type,1);      
  767.       fp->read(&len,1); 
  768.       se->type=type;
  769.       se->name=dp+sizeof(spec_entry);
  770.       fp->read(se->name,len);
  771.       fp->read(&flags,1); 
  772.  
  773.       se->size=fp->read_long();
  774.       se->offset=fp->read_long();
  775.       dp+=((sizeof(spec_entry)+len)+3)&(~3);
  776.     }
  777.   }
  778.   else 
  779.   {
  780.     total=0;
  781.     data=NULL;
  782.     entries=NULL;
  783.   }  
  784. }
  785.  
  786.  
  787. spec_directory::spec_directory(bFILE *fp)
  788. { startup(fp); }
  789.  
  790. spec_directory::spec_directory(FILE *fp)
  791. {
  792.   jFILE jfp(fp);
  793.   startup(&jfp);
  794. }
  795.  
  796. spec_directory::spec_directory()
  797.   total=0;
  798.   entries=NULL;
  799. }
  800.  
  801. /*
  802. spec_directory::spec_directory(char *filename)
  803. {
  804.   jFILE *fp;
  805.   if (filename)
  806.   {
  807.     fp=new jFILE(filename,"rb");
  808.     if (!fp->open_failure())
  809.       startup(fp);
  810.     else
  811.     {
  812.       total=0;
  813.       entries=NULL;
  814.     }
  815.     delete fp;
  816.   } else printf("NULL filename to spec_directory::spec_directory\n");
  817. }*/
  818.  
  819. int write_string(bFILE *fp, char *st)
  820. {
  821.   unsigned char length=strlen(st)+1;
  822.   if (fp->write(&length,1)!=1) return 0;
  823.   if (fp->write(st,length)!=length) return 0;
  824.   return 1;
  825. }
  826.  
  827. long spec_directory::data_start_offset()
  828. {
  829.   spec_entry *e;
  830.   long o=0,i;
  831.   for (i=0;i<total;i++) 
  832.     return entries[i]->offset;
  833.  
  834.   return SPEC_SIG_SIZE+2;     // if no entries, then no data, but return where it would
  835.                               // start anyway
  836.  
  837. long spec_directory::data_end_offset()
  838. {
  839.   spec_entry **e;
  840.   long o=0,i;
  841.   for (i=total-1,e=entries;i>=0;i--,e++)
  842.     return (*e)->offset+(*e)->size;
  843.  
  844.   return SPEC_SIG_SIZE+2;
  845.  
  846. int spec_directory::write(bFILE *fp)
  847. {
  848.  
  849.   char sig[SPEC_SIG_SIZE];
  850.   unsigned short tentries;
  851.   unsigned char flags=0;
  852.   unsigned long offset,data_size;
  853.   spec_entry **e;
  854.   strcpy(sig,SPEC_SIGNATURE);
  855.  
  856.   if (fp->write(sig,sizeof(sig))!=sizeof(sig))    return 0;
  857.   fp->write_short(total);
  858.  
  859.  
  860.   int i;
  861.   for (i=0,e=entries;i<total;i++,e++)
  862.   {
  863.     if (fp->write(&(*e)->type,1)!=1)                 return 0;
  864.     if (!write_string(fp,(*e)->name))                return 0;
  865.     flags=0;
  866.     if (fp->write(&flags,1)!=1)                     return 0; 
  867.  
  868.     data_size=long_to_intel((*e)->size); 
  869.     if (fp->write((char *)&data_size,4)!=4)              return 0; 
  870.     offset=long_to_intel((*e)->offset);
  871.     if (fp->write((char *)&offset,4)!=4)                  return 0; 
  872.  
  873.   }
  874.   return 1; 
  875. }
  876.  
  877. jFILE *spec_directory::write(char *filename)
  878. {
  879.   jFILE *fp;
  880.   fp=new jFILE(filename,"wb");
  881.   if (fp->open_failure()) { delete fp; return NULL; }
  882.   if (!write(fp))
  883.   {
  884.     delete fp;
  885.     return NULL;
  886.   } else return fp;
  887.  
  888. }
  889.  
  890. unsigned short read_short(FILE *fp)
  891. {
  892.   unsigned short x;
  893.   fread(&x,1,2,fp); 
  894.   return int_to_local(x);
  895. }
  896.  
  897. unsigned long read_long(FILE *fp)
  898. {
  899.   unsigned long x;
  900.   fread(&x,1,4,fp);
  901.   return (long)long_to_local(x);
  902. }
  903. void write_short(FILE *fp, unsigned short x)
  904. {
  905.   x=int_to_local(x);
  906.   fwrite(&x,1,2,fp);
  907. }
  908.  
  909. void write_long(FILE *fp, unsigned long x)
  910. {
  911.   x=long_to_local(x);
  912.   fwrite(&x,1,4,fp);
  913. }
  914.  
  915. unsigned char read_byte(FILE *fp) { return fgetc(fp)&0xff; }
  916. void write_byte(FILE *fp, unsigned char x) { fputc(x,fp); }
  917.  
  918. unsigned short read_other_long(FILE *fp)
  919. {
  920.   unsigned long x;
  921.   fread(&x,1,4,fp);
  922.   return big_long_to_local(x);
  923. }
  924.  
  925. unsigned long read_other_short(FILE *fp)
  926. {
  927.   unsigned short x;
  928.   fread(&x,1,2,fp);
  929.   return big_short_to_local(x);
  930. }
  931.  
  932.  
  933. void write_other_short(FILE *fp, unsigned short x)
  934. {
  935.   x=big_short_to_local(x);
  936.   fwrite(&x,1,2,fp);
  937. }
  938.  
  939. void write_other_long(FILE *fp, unsigned long x)
  940. {
  941.   x=big_long_to_local(x);
  942.   fwrite(&x,1,4,fp);
  943. }
  944.  
  945. void spec_directory::remove(spec_entry *e) 
  946.   int i;
  947.   for (i=0;i<total && entries[i]!=e;i++);            // find the entry in the array first
  948.   
  949.   if (entries[i]==e)                                 // make sre it was found
  950.   {
  951.     delete e;
  952.     total--;
  953.     for (;i<total;i++)                               // compact the pointer array
  954.       entries[i]=entries[i+1];
  955.     entries=(spec_entry **)jrealloc(entries,sizeof(spec_entry *)*total,"spec_directory::entries");
  956.   }
  957.   else
  958.     printf("Spec_directory::remove bad entry pointer\n");
  959. }
  960.  
  961.  
  962.  
  963. void spec_directory::add_by_hand(spec_entry *e) 
  964.   total++;
  965.   entries=(spec_entry **)jrealloc(entries,sizeof(spec_entry *)*total,"spec_directory::entries");
  966.   entries[total-1]=e;
  967. }
  968.  
  969. void spec_directory::delete_entries()   // if the directory was created by hand instead of by file
  970. {
  971.   int i;
  972.   for (i=0;i<total;i++)
  973.     delete entries[i];
  974.  
  975.   if (total)
  976.     jfree(entries);
  977.  
  978.   total=0;
  979.   entries=0;
  980.   data=0;
  981. }
  982.  
  983.  
  984. void note_open_fd(int fd, char *str)
  985. {
  986.   total_files_open++;
  987. }
  988.  
  989. void note_close_fd(int fd)
  990. {
  991.   total_files_open--;
  992. }
  993.  
  994.  
  995. void list_open_fds()
  996. {
  997.   printf("Total open dos fds=%d\n",total_files_open);
  998. }
  999.  
  1000.